#include "histogram.h"
#include <QDebug>
void minMax(QImage &image, int &min, int &max)
{
    int height = image.height();
    int width = image.width();
    min = 255;
    max = 0;
    for(int i = 0; i < height; i++)
    {
        const quint8 *pData = (const quint8 *)image.constScanLine(i);

        for(int j = 0; j < width; j++)
        {
            if( pData[j] < min) min = pData[j];
            if( pData[j] > max) max = pData[j];
        }
    }
}
void  applyThreshold(QImage &image, quint8 th)
{
	if(image.format() != QImage::Format_Indexed8)
    {
        return ;
    }
    int height = image.height();
    int width = image.width();

    for(int i = 0; i < height; i ++)
    {
        uchar *pSrc = (uchar *)image.scanLine(i);
        for( int j = 0; j < width; j ++)
        {
             pSrc[j] = (pSrc[j] > th)? 255: 0;
        }
    }
    return;
}
QImage threshold(const QImage &image, quint8 th)
{
    int height = image.height();
    int width = image.width();
    QImage ret(width, height, QImage::Format_Indexed8);
    ret.setColorCount(256);
    for(int i = 0; i < 256; i++)
    {
        ret.setColor(i, qRgb(i, i, i));
    }

    for(int i = 0; i < height; i ++)
    {
        const uchar *pSrc = (uchar *)image.constScanLine(i);
        uchar *pDest = (uchar *)ret.scanLine(i);
        for( int j = 0; j < width; j ++)
        {
             pDest[j] = (pSrc[j] > th)? 255: 0;
        }
    }
    return ret;
}

int otsu(const QImage &image)
{
    double hist[256];
    normalizedHistogram(image, hist);

    double omega[256];
    double mu[256];

    omega[0] = hist[0];
    mu[0] = 0;
    for(int i = 1; i < 256; i++)
    {
        omega[i] = omega[i-1] + hist[i]; //累积分布函数
        mu[i] = mu[i-1] + i * hist[i];
    }
    double mean = mu[255];// 灰度平均值
    double max = 0;
    int k_max = 0;
    for(int k = 1; k < 255; k++)
    {
        double PA = omega[k]; // A类所占的比例
        double PB = 1 - omega[k]; //B类所占的比例
        double value = 0;
        if( fabs(PA) > 0.001 && fabs(PB) > 0.001)
        {       
            double MA = mu[k] / PA; //A 类的灰度均值
            double MB = (mean - mu[k]) / PB;//B类灰度均值
            value = pow(PA, 0.5) * (MA - mean) * (MA - mean) + pow(PB, 0.5) * (MB - mean) * (MB - mean);//类间方差

            if (value > max)
            {
                max = value;
                k_max = k;
            }
        }
        qDebug() <<k << " " << hist[k] << " " << value;
    }
    return k_max;
}

QVector<int> histogram(QImage &image)
{
    QVector<int> hist(256, 0);
    int height = image.height();
    int width = image.width();
    if(image.format() != QImage::Format_Indexed8)
    {
        return hist;
    }
    for(int i = 0; i < height; i++)
    {
        const quint8 *pData = (const quint8 *)image.constScanLine(i);
        for(int j = 0; j < width; j++)
        {
            ++hist[ pData[j] ];
        }
    }
    return hist;
}

bool normalizedHistogram(const QImage &image, double hist[256])
{
    for(int i = 0; i < 256; i++)
    {
        hist[i] = 0.0;
    }
    int height = image.height();
    int width = image.width();
    int N = height * width;
    if(image.format() != QImage::Format_Indexed8)
    {
        return false;
    }
    for(int i = 0; i < height; i++)
    {
        const quint8 *pData = (const quint8 *)image.constScanLine(i);
        for(int j = 0; j < width; j++)
        {
            ++hist[ pData[j] ];
        }
    }
    for(int i = 0; i < 256; i++)
    {
        hist[i] = hist[i] / N;
    }
    return true;
}

bool histogram(QImage &image, unsigned int hist[256])
{
	for(int i = 0; i < 256; i++)
    {
        hist[i] = 0;
    }
    int height = image.height();
    int width = image.width();
    if(image.format() != QImage::Format_Indexed8)
    {
        return false;
    }
    for(int i = 0; i < height; i++)
    {
        const quint8 *pData = (const quint8 *)image.constScanLine(i);
        for(int j = 0; j < width; j++)
        {
            ++hist[ pData[j] ];
        }
    }
    return true;
}
bool histogram(const QImage &image, unsigned int red[256], unsigned int green[256], unsigned int blue[256])
{
    for(int i = 0; i < 256; i++)
    {
        red[i] = 0;
        green[i] = 0;
        blue[i] = 0;
    }
	if( image.isNull() )
	{
		return false;
	}
    int height = image.height();
    int width = image.width();
    //int N = height * width;
	
	switch(image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        for(int i = 0; i < height; i++)
		{
			const QRgb *pData = (const QRgb *)image.constScanLine(i);
			for(int j = 0; j < width; j++)
			{
				++red[ qRed(pData[j]) ];
				++green[ qGreen(pData[j]) ];
				++blue[ qBlue(pData[j]) ];
			}
		}
		return true;
        break;
    case QImage::Format_RGB888:
		for(int i = 0; i < height; i++)
		{
			const quint8 *pData = (const quint8 *)image.constScanLine(i);
			for(int j = 0; j < width; j++)
			{
				++red[ qRed(pData[3 * j]) ];
				++green[ qGreen(pData[3 * j + 1]) ];
				++blue[ qBlue(pData[3 * j + 2]) ];
			}
		}
		return true;
        break;
    case QImage::Format_Indexed8:
        return false;
		break;
    }
	return false;
}

bool normalizedHistogram(const QImage &image, double red[256], double green[256], double blue[256])
{
    for(int i = 0; i < 256; i++)
    {
        red[i] = 0.0;
        green[i] = 0.0;
        blue[i] = 0.0;
    }
    if( image.isNull() )
    {
        return false;
    }
    int height = image.height();
    int width = image.width();
    int N = height * width;

    switch(image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        for(int i = 0; i < height; i++)
        {
            const QRgb *pData = (const QRgb *)image.constScanLine(i);
            for(int j = 0; j < width; j++)
            {
                ++red[ qRed(pData[j]) ];
                ++green[ qGreen(pData[j]) ];
                ++blue[ qBlue(pData[j]) ];
            }
        }
        for(int i = 0; i < 256; i++)
        {
            red[i] = red[i] / N;
            green[i] = green[i] / N;
            blue[i] = blue[i] / N;
        }
        return true;
        break;
    case QImage::Format_RGB888:
        for(int i = 0; i < height; i++)
        {
            const quint8 *pData = (const quint8 *)image.constScanLine(i);
            for(int j = 0; j < width; j++)
            {
                ++red[ qRed(pData[3 * j]) ];
                ++green[ qGreen(pData[3 * j + 1]) ];
                ++blue[ qBlue(pData[3 * j + 2]) ];
            }
        }
        for(int i = 0; i < 256; i++)
        {
            red[i] = red[i] / N;
            green[i] = green[i] / N;
            blue[i] = blue[i] / N;
        }
        return true;
        break;
    case QImage::Format_Indexed8:
        return false;
        break;
    }
    return false;
}

QImage histogramEqualization(QImage &image)
{
    int height = image.height();
    int width = image.width();
    int N = height * width;

    QVector<int> hist = histogram(image);

    QVector<quint8> map(256, 0);
    int sum = 0;
    for(int i = 0; i < 256; i++)
    {
        sum += hist[i];
        map[i] = sum * 255 / N;
    }
    //qDebug() << map;
    QImage im(width, height, QImage::Format_Indexed8);
    im.setColorCount(256);
    for(int i = 0; i < 256; i++)
    {
        im.setColor(i, qRgb(i, i, i));
    }
    for(int i = 0; i < height; i++)
    {
        const quint8 *src = (const quint8 *)image.constScanLine(i);
        quint8 *des = (quint8 *)im.scanLine(i);
        for(int j = 0; j < width; j++)
        {
            des[j] = map[src[j]];
        }
    }
    return im;
}

//直方图正规化，将图像图像最亮的地方线性拉伸到 255，最暗的地方线性拉伸到 0
void applyHistogramNormalization(QImage &image)
{
    int min = 255, max = 0;
    int height = image.height();
    int width = image.width();
    if( image.format() != QImage::Format_Indexed8)
    {
        return;
    }
    minMax(image, min, max);
    int range = max - min;
    for(int i = 0; i < height; i++)
    {
        quint8 *src = (quint8 *)image.scanLine(i);
        for(int j = 0; j < width; j++)
        {
            src[j] = (src[j] - min) * 255 / range;
        }
    }
    return;
}
//直方图正规化，将图像图像最亮的地方线性拉伸到 255，最暗的地方线性拉伸到 0
QImage histogramNormalization(QImage &image)
{
    int min = 255, max = 0;
    int height = image.height();
    int width = image.width();
	if( image.format() != QImage::Format_Indexed8)
	{
		return QImage(0,0);
	}
    QImage im(width, height, QImage::Format_Indexed8);
    im.setColorCount(256);
    for(int i = 0; i < 256; i++)
    {
        im.setColor(i, qRgb(i, i, i));
    }
    minMax(image, min, max);
    int range = max - min;
    for(int i = 0; i < height; i++)
    {
        const quint8 *src = (const quint8 *)image.constScanLine(i);
        quint8 *des = (quint8 *)im.scanLine(i);
        for(int j = 0; j < width; j++)
        {
            des[j] = (src[j] - min) * 255 / range;
        }
    }
    return im;
}
QImage toRGB32( const QImage &image )
{
    int height = image.height();
    int width = image.width();
    QImage ret(width, height, QImage::Format_ARGB32);
    for(int i = 0; i < height; i ++)
    {
        const uchar *pSrc = (uchar *)image.constScanLine(i);
        QRgb *pDest = (QRgb *)ret.scanLine(i);

        for( int j = 0; j < width; j ++)
        {
             pDest[j] = qRgb(pSrc[j], pSrc[j], pSrc[j]);
        }
    }
    return ret;
}

QImage toGray( const QImage &image )
{
    int height = image.height();
    int width = image.width();
    QImage ret(width, height, QImage::Format_Indexed8);
    ret.setColorCount(256);
    for(int i = 0; i < 256; i++)
    {
        ret.setColor(i, qRgb(i, i, i));
    }
    switch(image.format())
    {
    case QImage::Format_Indexed8:
        for(int i = 0; i < height; i ++)
        {
            const uchar *pSrc = (uchar *)image.constScanLine(i);
            uchar *pDest = (uchar *)ret.scanLine(i);
            memcpy(pDest, pSrc, width);
        }
        break;
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32:
    case QImage::Format_ARGB32_Premultiplied:
        for(int i = 0; i < height; i ++)
        {
            const QRgb *pSrc = (QRgb *)image.constScanLine(i);
            uchar *pDest = (uchar *)ret.scanLine(i);

            for( int j = 0; j < width; j ++)
            {
                 pDest[j] = qGray(pSrc[j]);
            }
        }
        break;
    }
    return ret;
}
